package com.cskaoyan.wordmemorize.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cskaoyan.wordmemorize.converter.ReviewConverter;
import com.cskaoyan.wordmemorize.dao.entity.UserCheckinStatisticsDO;
import com.cskaoyan.wordmemorize.dao.entity.UserRevStatisticsDO;
import com.cskaoyan.wordmemorize.dao.entity.UserVocBoundStatisticsDO;
import com.cskaoyan.wordmemorize.dao.entity.UserVocRevDO;
import com.cskaoyan.wordmemorize.dao.mapper.UserCheckinStatisticsMapper;
import com.cskaoyan.wordmemorize.dao.mapper.UserRevStatisticsMapper;
import com.cskaoyan.wordmemorize.dao.mapper.UserVocBoundStatisticsMapper;
import com.cskaoyan.wordmemorize.dao.mapper.UserVocRevMapper;
import com.cskaoyan.wordmemorize.dto.admin.PageDTO;
import com.cskaoyan.wordmemorize.dto.app.DownLoadUserReviewDTO;
import com.cskaoyan.wordmemorize.dto.app.UserReviewStatisticsDTO;
import com.cskaoyan.wordmemorize.dto.app.UserVocRevDTO;
import com.cskaoyan.wordmemorize.request.PageRequest;
import com.cskaoyan.wordmemorize.request.UserReviewDataCommand;
import com.cskaoyan.wordmemorize.request.UserReviewStatisticsCommand;
import com.cskaoyan.wordmemorize.request.UserVocRevCommand;
import com.cskaoyan.wordmemorize.service.UserReviewService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.List;

@Service
public class UserReviewServiceImpl implements UserReviewService {

    @Autowired
    UserVocRevMapper userVocRevMapper;

    @Autowired
    UserRevStatisticsMapper userRevStatisticsMapper;

    @Autowired
    UserCheckinStatisticsMapper userCheckinStatisticsMapper;

    @Autowired
    ReviewConverter reviewConverter;

    @Autowired
    UserVocBoundStatisticsMapper userVocBoundStatisticsMapper;

    /**
     * 同步用户的复习数据
     *
     * @param command
     * @param userId
     */
    @Override
    public void synchronizeUserReviewData(UserReviewDataCommand command, Long userId) {
        // 1. 处理复习统计数据（合并当天数据）
        UserReviewStatisticsCommand revStatisticsCommand = command.getRevStatisticsCommand();
        LocalDate reviewDate = revStatisticsCommand.getReviewDate();
        Long studyTime = 0L;
        try {
            studyTime = Long.parseLong(revStatisticsCommand.getStudyTime());
        } catch (Exception e) {
            // 若转换失败，默认0
        }
        // 查询当天是否已有统计数据
        LambdaQueryWrapper<UserRevStatisticsDO> statQuery = new LambdaQueryWrapper<>();
        statQuery.eq(UserRevStatisticsDO::getUserId, userId)
                .eq(UserRevStatisticsDO::getReviewDate, reviewDate);
        UserRevStatisticsDO todayStat = userRevStatisticsMapper.selectOne(statQuery);
        if (todayStat == null) {
            // 没有则插入
            UserRevStatisticsDO newStat = new UserRevStatisticsDO();
            newStat.setUserId(userId);
            newStat.setVocNewCount(revStatisticsCommand.getVocNewCount());
            newStat.setVocReviewCount(revStatisticsCommand.getVocReviewCount());
            newStat.setTotalCount(revStatisticsCommand.getTotalCount());
            newStat.setForgetCount(revStatisticsCommand.getForgetCount());
            newStat.setUncertainCount(revStatisticsCommand.getUncertainCount());
            newStat.setKnownCount(revStatisticsCommand.getKnownCount());
            newStat.setSimpleCount(revStatisticsCommand.getSimpleCount());
            newStat.setStudyTime(studyTime);
            newStat.setReviewDate(reviewDate);
            userRevStatisticsMapper.insert(newStat);
        } else {
            if (todayStat.getKnownCount() == null)
                todayStat.setKnownCount(0);
            // 有则合并（累加各项）
            LambdaUpdateWrapper<UserRevStatisticsDO> updateStat = new LambdaUpdateWrapper<>();
            updateStat.eq(UserRevStatisticsDO::getUserId, userId)
                    .eq(UserRevStatisticsDO::getReviewDate, reviewDate)
                    .set(UserRevStatisticsDO::getVocNewCount,
                            (todayStat.getVocNewCount() == null ? 0 : todayStat.getVocNewCount())
                                    + (revStatisticsCommand.getVocNewCount() == null ? 0
                                    : revStatisticsCommand.getVocNewCount()))
                    .set(UserRevStatisticsDO::getVocReviewCount,
                            (todayStat.getVocReviewCount() == null ? 0 : todayStat.getVocReviewCount())
                                    + (revStatisticsCommand.getVocReviewCount() == null ? 0
                                    : revStatisticsCommand.getVocReviewCount()))
                    .set(UserRevStatisticsDO::getTotalCount,
                            (todayStat.getTotalCount() == null ? 0 : todayStat.getTotalCount())
                                    + (revStatisticsCommand.getTotalCount() == null ? 0
                                    : revStatisticsCommand.getTotalCount()))
                    .set(UserRevStatisticsDO::getForgetCount,
                            (todayStat.getForgetCount() == null ? 0 : todayStat.getForgetCount())
                                    + (revStatisticsCommand.getForgetCount() == null ? 0
                                    : revStatisticsCommand.getForgetCount()))
                    .set(UserRevStatisticsDO::getUncertainCount,
                            (todayStat.getUncertainCount() == null ? 0 : todayStat.getUncertainCount())
                                    + (revStatisticsCommand.getUncertainCount() == null ? 0
                                    : revStatisticsCommand.getUncertainCount()))
                    .set(UserRevStatisticsDO::getKnownCount,
                            (todayStat.getKnownCount() == null ? 0 : todayStat.getKnownCount())
                                    + (revStatisticsCommand.getKnownCount() == null ? 0
                                    : revStatisticsCommand.getKnownCount()))
                    .set(UserRevStatisticsDO::getSimpleCount,
                            (todayStat.getSimpleCount() == null ? 0 : todayStat.getSimpleCount())
                                    + (revStatisticsCommand.getSimpleCount() == null ? 0
                                    : revStatisticsCommand.getSimpleCount()))
                    .set(UserRevStatisticsDO::getStudyTime,
                            (todayStat.getStudyTime() == null ? 0L : todayStat.getStudyTime()) + studyTime);
            userRevStatisticsMapper.update(null, updateStat);
        }
        // 更新签到统计表的总学习时长
        LambdaUpdateWrapper<UserCheckinStatisticsDO> checkinUpdate = new LambdaUpdateWrapper<>();
        checkinUpdate.eq(UserCheckinStatisticsDO::getUserId, userId)
                .setSql("total_time = total_time + " + studyTime);
        userCheckinStatisticsMapper.update(null, checkinUpdate);
        // 遍历单词复习数据，只做update
        List<UserVocRevCommand> vocRevCommands = command.getVocRevCommands();
        if (vocRevCommands != null && !vocRevCommands.isEmpty()) {
            for (UserVocRevCommand vocRevCommand : vocRevCommands) {
                LambdaUpdateWrapper<UserVocRevDO> vocUpdate = new LambdaUpdateWrapper<>();
                vocUpdate.eq(UserVocRevDO::getUserId, userId)
                        .eq(UserVocRevDO::getVocId, vocRevCommand.getVocId());
                UserVocRevDO updateDO = new UserVocRevDO();
                updateDO.setFactor(vocRevCommand.getFactor());
                updateDO.setReviewInterval(vocRevCommand.getReviewInterval());
                updateDO.setNextReviewDate(vocRevCommand.getNextReviewDate());
                updateDO.setType(vocRevCommand.getType());
                updateDO.setFamiliarity(vocRevCommand.getFamiliarity());
                updateDO.setConsecutiveFailCount(vocRevCommand.getConsecutiveFailCount());
                userVocRevMapper.update(updateDO, vocUpdate);
            }
        }
    }

    /**
     * 下载用户的复习数据
     *
     * @param pageRequest
     * @param userId
     * @return
     */
    @Override
    public DownLoadUserReviewDTO downloadUserReviewData(PageRequest pageRequest, Long userId) {
        // 构建返回参数
        DownLoadUserReviewDTO downLoadUserReviewDTO = new DownLoadUserReviewDTO();

        LambdaQueryWrapper<UserVocRevDO> userVocRevDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userVocRevDOLambdaQueryWrapper.eq(UserVocRevDO::getUserId, userId);
        PageDTO<UserVocRevDTO> userVocRevDTOPageDTO = null;

        LambdaQueryWrapper<UserRevStatisticsDO> userRevStatisticsDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userRevStatisticsDOLambdaQueryWrapper.eq(UserRevStatisticsDO::getUserId, userId);
        PageDTO<UserReviewStatisticsDTO> userReviewStatisticsDTOPageDTO = null;

        // 前端接口，keyword不考虑
        // 不分页查询
        if (pageRequest.getPageNum() == null || pageRequest.getCount() == null || pageRequest.getCount() == 0) {
            // 查询单词数据
            List<UserVocRevDO> userVocRevDOS = userVocRevMapper.selectList(userVocRevDOLambdaQueryWrapper);
            userVocRevDTOPageDTO = reviewConverter.userVocRevPage2PageDTO(userVocRevDOS, (long) userVocRevDOS.size());

            // 查询复习统计数据
            List<UserRevStatisticsDO> userRevStatisticsDOS = userRevStatisticsMapper
                    .selectList(userRevStatisticsDOLambdaQueryWrapper);
            userReviewStatisticsDTOPageDTO = reviewConverter.userRevStatistcsPage2PageDTO(userRevStatisticsDOS,
                    (long) userRevStatisticsDOS.size());

        } else { // 分页查询
            // 查询单词数据
            Page<UserVocRevDO> userVocRevDOPage = new Page<>(pageRequest.getPageNum(), pageRequest.getCount());
            Page<UserVocRevDO> userVocRevDOPage1 = userVocRevMapper.selectPage(userVocRevDOPage,
                    userVocRevDOLambdaQueryWrapper);
            userVocRevDTOPageDTO = reviewConverter.userVocRevPage2PageDTO(userVocRevDOPage1.getRecords(),
                    userVocRevDOPage1.getTotal());

            // 查询复习统计数据
            Page<UserRevStatisticsDO> userRevStatisticsDOPage = new Page<>(pageRequest.getPageNum(),
                    pageRequest.getCount());
            Page<UserRevStatisticsDO> userRevStatisticsDOPage1 = userRevStatisticsMapper
                    .selectPage(userRevStatisticsDOPage, userRevStatisticsDOLambdaQueryWrapper);
            userReviewStatisticsDTOPageDTO = reviewConverter.userRevStatistcsPage2PageDTO(
                    userRevStatisticsDOPage1.getRecords(), userRevStatisticsDOPage1.getTotal());

        }

        downLoadUserReviewDTO.setUserVocRevPage(userVocRevDTOPageDTO);
        downLoadUserReviewDTO.setUserReviewStatisticsPage(userReviewStatisticsDTOPageDTO);

        return downLoadUserReviewDTO;
    }

    /**
     * 添加复习单词
     *
     * @param vocIds
     * @param userId
     */
    @Override
    public void addUserRovRev(List<Long> vocIds, Long userId) {
        // 如果vocIds为空，说明选择的单词都在数据库中
        if (vocIds.isEmpty()) {
            return;
        }
        vocIds.forEach(vocId -> {
            UserVocRevDO userVocRevDO = new UserVocRevDO();
            userVocRevDO.setUserId(userId);
            userVocRevDO.setVocId(vocId);
            userVocRevDO.setType(0);
            userVocRevMapper.insert(userVocRevDO);
        });

        /*// 更新单词统计数据
        LambdaUpdateWrapper<UserVocBoundStatisticsDO> userVocBoundStatisticsDOLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        userVocBoundStatisticsDOLambdaUpdateWrapper.eq(UserVocBoundStatisticsDO::getUserId, userId);

        userVocBoundStatisticsMapper.update(userVocBoundStatisticsDOLambdaUpdateWrapper);*/

        LambdaQueryWrapper<UserVocBoundStatisticsDO> userVocBoundStatisticsDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userVocBoundStatisticsDOLambdaQueryWrapper.eq(UserVocBoundStatisticsDO::getUserId, userId);
        UserVocBoundStatisticsDO userVocBoundStatisticsDO = userVocBoundStatisticsMapper.selectOne(userVocBoundStatisticsDOLambdaQueryWrapper);

        userVocBoundStatisticsDO.setOccupied(userVocBoundStatisticsDO.getOccupied() + vocIds.size());
        userVocBoundStatisticsDO.setAvailable(userVocBoundStatisticsDO.getAvailable() - vocIds.size());
        LambdaUpdateWrapper<UserVocBoundStatisticsDO> vocBoundStatisticsDOLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        vocBoundStatisticsDOLambdaUpdateWrapper.eq(UserVocBoundStatisticsDO::getUserId, userId);
        userVocBoundStatisticsMapper.update(userVocBoundStatisticsDO, vocBoundStatisticsDOLambdaUpdateWrapper);
    }
}
